package com.example.exercise.rule;

import com.example.exercise.common.Pojo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

public class DataInit {

    private static final Logger LOGGER = LoggerFactory.getLogger(DataInit.class);

    public static <T> boolean fieldExists(T data, String rule) {
        String rule1 = rule.replace("(", "").replace(")", "");
        String[] ruleArr = rule1.split("&&|\\|\\|");
        Class<?> clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (String str : ruleArr) {
            boolean bool = false;
            String[] obj = ExpInit.getExp(str);
            if (obj == null || "".equals(obj[0]) || "".equals(obj[1])) {
                LOGGER.error("逻辑表达式{}格式错误", str);
                return false;
            }
            String expLeft = obj[0];
            if(!expLeft.contains(".")){
                for (Field f : fields) {
                    if (f.getName().equals(expLeft)) {
                        bool = true;
                        break;
                    }
                }
            }
            if (!bool && expLeft.contains(".")){
                t:for (Field f : fields) {
                    Class<?> clazz1 = f.getType();
                    if(clazz1.getSuperclass().getName().endsWith(".Pojo")){
                        Field[] fields1 = clazz1.getDeclaredFields();
                        for (Field f1 : fields1) {
                            if(obj[0].startsWith(f.getName() + "." + f1.getName())){
                                bool = true;
                                break t;
                            }
                        }
                    }
                }
            }

            if (!bool) {
                LOGGER.error("字段{}不存在", str);
                return false;
            }

        }
        return true;
    }

    public static <T extends Pojo> Map<String, Object> dataToMap(T data, String format) {
        Map<String, Object> map = new HashMap<>();
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        Class<?> clazz = data.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            Object o = null;
            try {
                o = getFieldValue(data, field, fieldName);
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NoSuchFieldException e) {
                e.printStackTrace();
            }
            if(o != null){
                if(field.getType() == Date.class){
                    map.put(fieldName, dateFormat.format(o));
                }else{
                    map.put(fieldName, o);
                }
            }
        }
        return map;
    }

    public static <T extends Pojo> String preHandler(T data, String rule){
        rule = ExpInit.ruleInit(rule);
        if(rule == null || !ExpInit.verifyRuleExpression(rule)){
            LOGGER.error("表达式错误");
            return null;
        }
        if(!fieldExists(data, rule)){
            LOGGER.error("规则表达式有多余的字段");
            return null;
        }
        return getRuleReplaced(data, rule);
    }

    public static <T extends Pojo> String preHandlerForList(T data, String rule){
        String ruleExp = preHandle(data, rule);
        if(ruleExp == null){
            LOGGER.error("表达式错误");
            return null;
        }
        if(!fieldExists(data, rule)){
            LOGGER.error("规则表达式有多余的字段");
            return null;
        }
        return ruleExp;
    }

    public static <T extends Pojo> String getRuleReplaced(T data, String ruleString) {
        String ruleNoBrackets = ruleString.replace("(", "").replace(")", "");
        String[] ruleStringArr = ruleNoBrackets.split("&&|\\|\\|");
        for (String ruleStringOne : ruleStringArr) {
            String[] expOne = ruleStringOne.split("[<>=!]");
            if (expOne.length >= 2) {
                String expLeft = expOne[0].trim();
                String fieldName = ExpInit.getReplacedFieldName(expLeft);
                Object o = null;
                try {
                    o = getFieldValue(data, null, fieldName);
                } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | NoSuchFieldException e) {
                    e.printStackTrace();
                }
                if(o == null){
                    ruleString = ruleString.replace(ruleStringOne.trim(), "false");
                }else{
                    if (!expLeft.contains(".")) {
                        String ruleStringOneReplaced = ruleStringOne.replace(expLeft, fieldName);
                        ruleString = ruleString.replace(ruleStringOne.trim(), ruleStringOneReplaced);
                    }
                }
            }
        }
        return ruleString;
    }

    public static <T extends Pojo> String preHandle(T data, String rule) {
        if (rule == null || "".equals(rule.trim())) {
            LOGGER.error("规则表达式不能为空");
            return null;
        }
        rule = ExpInit.ruleInit(rule);
        if (rule == null || !ExpInit.verifyRuleExpression(rule)) {
            return null;
        }
        return getRuleReplaced(data, rule);
    }

    private static <T extends Pojo> Object getFieldValue(T data, Field field, String fieldName) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class<?> clazz = data.getClass();
        if(field == null){
            field = clazz.getDeclaredField(fieldName);
        }
        if(fieldName == null){
            fieldName = field.getName();
        }
        String getterMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        Method method = clazz.getDeclaredMethod(getterMethodName);
        return method.invoke(data);
    }

    public static <T extends Pojo> String transExpWithSubDateField(T data, String ruleExp) {
        List<String> subDateFields = getPojoDateFields(data);
        if(subDateFields.isEmpty()){
            return ruleExp;
        }
        String ruleNoBrackets = ruleExp.replace("(", "").replace(")", "");
        String[] ruleStringArr = ruleNoBrackets.split("&&|\\|\\|");
        for (String ruleStringOne : ruleStringArr) {
            if(!ruleStringOne.trim().equals("true") && !ruleStringOne.trim().equals("false")){
                String expLeft = ruleStringOne.split("[<>=!]")[0].trim();
                String expleftNoPoint = expLeft.replace(".", "");
                if(expleftNoPoint.length() + 1 == expLeft.length() && subDateFields.contains(expLeft)){
                    String expLeftReplaced = "clazzDateFormat.format(" + expLeft + ")";
                    String expReplaced = ruleStringOne.replace(expLeft, expLeftReplaced);
                    ruleExp = ruleExp.replace(ruleStringOne.trim(), expReplaced);
                }
            }
        }
        return ruleExp;
    }

    public static <T extends Pojo> String transExpWithDateField(T data, String ruleExp, String prefix) {
        List<String> dateFields = getDateFields(data);
        List<String> subDateFields = getPojoDateFields(data);
        prefix = prefix == null?"":prefix;
        if(dateFields.isEmpty() && subDateFields.isEmpty() && "".equals(prefix)){
            return ruleExp;
        }
        String ruleNoBrackets = ruleExp.replace("(", "").replace(")", "");
        String[] ruleStringArr = ruleNoBrackets.split("&&|\\|\\|");
        for (String ruleStringOne : ruleStringArr) {
            if(!ruleStringOne.trim().equals("true") && !ruleStringOne.trim().equals("false")){
                String expLeft = ruleStringOne.split("[<>=!]")[0].trim();
                String expleftNoPoint = expLeft.replace(".", "");
                if((expleftNoPoint.length() + 1 == expLeft.length() && subDateFields.contains(expLeft))
                     || (expleftNoPoint.length() == expLeft.length() && dateFields.contains(expLeft))){
                    String expLeftReplaced = "clazzDateFormat.format(" + prefix + expLeft + ")";
                    String expReplaced = ruleStringOne.replace(expLeft, expLeftReplaced);
                    ruleExp = ruleExp.replace(ruleStringOne.trim(), expReplaced);
                }else{
                    if(!"".equals(prefix)){
                        ruleExp = ruleExp.replace(ruleStringOne.trim(), prefix + ruleStringOne.trim());
                    }
                }
            }
        }
        return ruleExp;
    }

    private static <T extends Pojo> List<String> getDateFields(T data) {
        List<String> list = new ArrayList<>();
        Field[] fields = data.getClass().getDeclaredFields();
        for (Field field : fields) {
            if(field.getType() == Date.class){
                list.add(field.getName());
            }
        }
        return list;
    }

    private static <T extends Pojo> List<String> getPojoDateFields(T data) {
        List<String> list = new ArrayList<>();
        Field[] fields = data.getClass().getDeclaredFields();
        for (Field field : fields) {
            Class<?> clazz = field.getType();
            if(clazz.getSuperclass().getName().endsWith(".Pojo")){
                Field[] fields1 = clazz.getDeclaredFields();
                for (Field field1 : fields1) {
                    if(field1.getType() == Date.class){
                        list.add(field.getName() + "." + field1.getName());
                    }
                }
            }

        }
        return list;
    }
}
